﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HumanWorkflow.SemanticModel;
using HumanWorkflow.LexicalModel;

namespace HumanWorkflow.InternalDsl
{
    public class HumanWorkflowBuilder
    {
        LexicalModelContext lexicalModel;

        public HumanWorkflowBuilder(LexicalModelContext lexicalModelContext)
        {
            lexicalModel = lexicalModelContext;
        }

        #region HumanWorkflow

        public static HumanWorkflowBuilder HumanWorkflow(string name)
        {
            LexicalModelContext lexicalModel = new LexicalModelContext();
            lexicalModel.WorkflowToken.Name = name;

            return new HumanWorkflowBuilder(lexicalModel);
        }

        public HumanWorkflowSemanticModel End()
        {
            NewStepToken(null);
            return lexicalModel.TransformToSemanticModel();
        }
        
        #endregion

        #region Context variables


        StepToken currentStepToken;
        TransitionToken currentTransitionToken;

        void NewStepToken(StepToken newStepToken)
        {
            NewTransitionToken(null);

            if (currentStepToken != null)
            {
                lexicalModel.StepTokens.Add(currentStepToken);
            }

            currentStepToken = newStepToken;
        }

        void NewTransitionToken(TransitionToken newTransitionToken)
        {
            if (currentTransitionToken != null)
            {
                currentStepToken.OutTransitions.Add(currentTransitionToken);
            }

            currentTransitionToken = newTransitionToken;
        }

        #endregion

        #region Steps

        public HumanWorkflowBuilder Initial(string name)
        {
            StepToken stepToken = new StepToken { Name = name, StepType = StepTypeEnum.Initial};
            NewStepToken(stepToken);

            return this;
        }

        public HumanWorkflowBuilder HumanWork(string name)
        {
            StepToken stepToken = new StepToken { Name = name, StepType = StepTypeEnum.HumanWork };
            NewStepToken(stepToken);

            return this;
        }


        public HumanWorkflowBuilder SystemCommand(string name)
        {
            StepToken stepToken = new StepToken { Name = name, StepType = StepTypeEnum.SystemCommand};
            NewStepToken(stepToken);

            return this;
        }

        public HumanWorkflowBuilder Decision(string name)
        {
            StepToken stepToken = new StepToken { Name = name, StepType = StepTypeEnum.Decision};
            NewStepToken(stepToken);

            return this;
        }


        public HumanWorkflowBuilder Final(string name)
        {
            StepToken stepToken = new StepToken { Name = name, StepType = StepTypeEnum.Final};
            NewStepToken(stepToken);

            return this;
        }

        public HumanWorkflowBuilder DoneBy(string roleName)
        {
            if (currentStepToken.StepType == StepTypeEnum.HumanWork)
            {
                currentStepToken.Role = roleName;
            }
            else
            {
                throw new Exception("Role is only applicable to HumanWork type.");
            }

            return this;
        }

        #endregion

        #region Transiton

        public HumanWorkflowBuilder GoesTo(string stepName)
        {
            NewTransitionToken(new TransitionToken { ToStepName = stepName });

            return this;
        }

        public HumanWorkflowBuilder WhenEvent(string eventName)
        {
            if (currentTransitionToken != null)
            {
                currentTransitionToken.Name = eventName;
            }
            else
            {
                throw new Exception("When event is only applicable to transitions. (Call first GoesTo.)");
            }

            return this;
        }

        #endregion
    }
}
